﻿using System;
using System.Globalization;
using System.Text;

namespace NetTopologySuite.Mathematics
{
	[Serializable]
	public struct DD : IComparable, IComparable<DD>
	{
		private static DD CreateNaN()
		{
			return new DD(double.NaN, double.NaN);
		}

		public static DD ValueOf(string str)
		{
			return DD.Parse(str);
		}

		public static explicit operator DD(string val)
		{
			return DD.Parse(val);
		}

		public static DD ValueOf(double x)
		{
			return new DD(x);
		}

		public static implicit operator DD(double val)
		{
			return new DD(val);
		}

		public DD(double x)
		{
			this = new DD(x, 0.0);
		}

		public DD(double hi, double lo)
		{
			this._hi = hi;
			this._lo = lo;
		}

		public DD(DD dd)
		{
			this._hi = dd._hi;
			this._lo = dd._lo;
		}

		public DD(string str)
		{
			this = new DD(DD.Parse(str));
		}

		public static DD Copy(DD dd)
		{
			return new DD(dd);
		}

		public object Clone()
		{
			return new DD(this._hi, this._lo);
		}

		[Obsolete("Use operator +")]
		public DD Add(DD y)
		{
			return this + y;
		}

		public static DD operator +(DD lhs, DD rhs)
		{
			double num = lhs._hi + rhs._hi;
			double num2 = lhs._lo + rhs._lo;
			double num3 = num - lhs._hi;
			double num4 = num2 - lhs._lo;
			double num5 = num - num3;
			double num6 = num2 - num4;
			num5 = rhs._hi - num3 + (lhs._hi - num5);
			num6 = rhs._lo - num4 + (lhs._lo - num6);
			num3 = num5 + num2;
			double num7 = num + num3;
			double num8 = num3 + (num - num7);
			num3 = num6 + num8;
			double num9 = num7 + num3;
			return new DD(num9, num3 + (num7 - num9));
		}

		public static DD operator +(DD lhs, double rhs)
		{
			return lhs + new DD(rhs, 0.0);
		}

		public static DD operator -(DD lhs, DD rhs)
		{
			return lhs + rhs.Negate();
		}

		public static DD operator -(DD lhs, double rhs)
		{
			return lhs + new DD(-rhs, 0.0);
		}

		[Obsolete("Use Operator +")]
		public DD Add(double y)
		{
			return this + y;
		}

		[Obsolete("Use operator -")]
		public DD Subtract(DD y)
		{
			return this.Add(y.Negate());
		}

		[Obsolete("Use operator -")]
		public DD Subtract(double y)
		{
			return this.Add(-y);
		}

		public DD Negate()
		{
			if (DD.IsNaN(this))
			{
				return this;
			}
			return new DD(-this._hi, -this._lo);
		}

		[Obsolete("Use *-operator instead")]
		public DD Multiply(DD y)
		{
			return this * y;
		}

		[Obsolete("Use *-operator instead")]
		public DD Multiply(double y)
		{
			return this * y;
		}

		public static DD operator *(DD lhs, double rhs)
		{
			return lhs * new DD(rhs, 0.0);
		}

		public static DD operator *(DD lhs, DD rhs)
		{
			if (DD.IsNaN(rhs))
			{
				return DD.CreateNaN();
			}
			double num = 134217729.0 * lhs._hi;
			double num2 = num - lhs._hi;
			double num3 = 134217729.0 * rhs._hi;
			num2 = num - num2;
			double num4 = lhs._hi - num2;
			double num5 = num3 - rhs._hi;
			num = lhs._hi * rhs._hi;
			num5 = num3 - num5;
			double num6 = rhs._hi - num5;
			num3 = num2 * num5 - num + num2 * num6 + num4 * num5 + num4 * num6 + (lhs._hi * rhs._lo + lhs._lo * rhs._hi);
			double num7 = num + num3;
			num2 = num - num7;
			double lo = num3 + num2;
			return new DD(num7, lo);
		}

		public DD Divide(DD y)
		{
			double num = this._hi / y._hi;
			double num2 = 134217729.0 * num;
			double num3 = num2 - num;
			double num4 = 134217729.0 * y._hi;
			num3 = num2 - num3;
			double num5 = num - num3;
			double num6 = num4 - y._hi;
			double num7 = num * y._hi;
			num6 = num4 - num6;
			double num8 = y._hi - num6;
			num4 = num3 * num6 - num7 + num3 * num8 + num5 * num6 + num5 * num8;
			num2 = (this._hi - num7 - num4 + this._lo - num * y._lo) / y._hi;
			num4 = num + num2;
			double hi = num4;
			double lo = num - num4 + num2;
			return new DD(hi, lo);
		}

		[Obsolete("Use /-operator instead")]
		public DD Divide(double y)
		{
			return this / y;
		}

		public static DD operator /(DD lhs, double rhs)
		{
			return lhs / new DD(rhs, 0.0);
		}

		public static DD operator /(DD lhs, DD rhs)
		{
			if (DD.IsNaN(rhs))
			{
				return DD.CreateNaN();
			}
			double num = lhs._hi / rhs._hi;
			double num2 = 134217729.0 * num;
			double num3 = num2 - num;
			double num4 = 134217729.0 * rhs._hi;
			num3 = num2 - num3;
			double num5 = num - num3;
			double num6 = num4 - rhs._hi;
			double num7 = num * rhs._hi;
			num6 = num4 - num6;
			double num8 = rhs._hi - num6;
			num4 = num3 * num6 - num7 + num3 * num8 + num5 * num6 + num5 * num8;
			num2 = (lhs._hi - num7 - num4 + lhs._lo - num * rhs._lo) / rhs._hi;
			num4 = num + num2;
			return new DD(num4, num - num4 + num2);
		}

		public DD Reciprocal()
		{
			double num = 1.0 / this._hi;
			double num2 = 134217729.0 * num;
			double num3 = num2 - num;
			double num4 = 134217729.0 * this._hi;
			num3 = num2 - num3;
			double num5 = num - num3;
			double num6 = num4 - this._hi;
			double num7 = num * this._hi;
			num6 = num4 - num6;
			double num8 = this._hi - num6;
			num4 = num3 * num6 - num7 + num3 * num8 + num5 * num6 + num5 * num8;
			num2 = (1.0 - num7 - num4 - num * this._lo) / this._hi;
			double num9 = num + num2;
			double lo = num - num9 + num2;
			return new DD(num9, lo);
		}

		public DD Min(DD x)
		{
			if (!this.LessThan(x))
			{
				return x;
			}
			return this;
		}

		public DD Max(DD x)
		{
			if (!this.GreaterOrEqualThan(x))
			{
				return x;
			}
			return this;
		}

		public DD Floor()
		{
			if (DD.IsNaN(this))
			{
				return DD.NaN;
			}
			double num = Math.Floor(this._hi);
			double lo = 0.0;
			if (num == this._hi)
			{
				lo = Math.Floor(this._lo);
			}
			return new DD(num, lo);
		}

		public DD Ceiling()
		{
			if (DD.IsNaN(this))
			{
				return DD.NaN;
			}
			double num = Math.Ceiling(this._hi);
			double lo = 0.0;
			if (num == this._hi)
			{
				lo = Math.Ceiling(this._lo);
			}
			return new DD(num, lo);
		}

		public int Signum()
		{
			if (this._hi > 0.0)
			{
				return 1;
			}
			if (this._hi < 0.0)
			{
				return -1;
			}
			if (this._lo > 0.0)
			{
				return 1;
			}
			if (this._lo < 0.0)
			{
				return -1;
			}
			return 0;
		}

		public DD Rint()
		{
			if (DD.IsNaN(this))
			{
				return this;
			}
			return (this + 0.5).Floor();
		}

		public DD Truncate()
		{
			if (DD.IsNaN(this))
			{
				return DD.NaN;
			}
			if (!this.IsPositive())
			{
				return this.Ceiling();
			}
			return this.Floor();
		}

		public DD Abs()
		{
			if (DD.IsNaN(this))
			{
				return DD.NaN;
			}
			if (!this.IsNegative)
			{
				return new DD(this);
			}
			return this.Negate();
		}

		public DD Sqr()
		{
			return this * this;
		}

		public static DD Sqr(double x)
		{
			return DD.ValueOf(x) * x;
		}

		public DD Sqrt()
		{
			if (this.IsZero)
			{
				return DD.ValueOf(0.0);
			}
			if (this.IsNegative)
			{
				return DD.NaN;
			}
			double num = 1.0 / System.Math.Sqrt(this._hi);
			DD lhs = DD.ValueOf(this._hi * num);
			double rhs = (this - lhs.Sqr())._hi * (num * 0.5);
			return lhs + rhs;
		}

		public static DD Sqrt(double x)
		{
			return DD.ValueOf(x).Sqrt();
		}

		public DD Pow(int exp)
		{
			if ((double)exp == 0.0)
			{
				return DD.ValueOf(1.0);
			}
			DD dd = new DD(this);
			DD dd2 = DD.ValueOf(1.0);
			int i = System.Math.Abs(exp);
			if (i > 1)
			{
				while (i > 0)
				{
					if (i % 2 == 1)
					{
						dd2 *= dd;
					}
					i /= 2;
					if (i > 0)
					{
						dd = dd.Sqr();
					}
				}
			}
			else
			{
				dd2 = dd;
			}
			if (exp < 0)
			{
				return dd2.Reciprocal();
			}
			return dd2;
		}

		public double ToDoubleValue()
		{
			return this._hi + this._lo;
		}

		public int ToIntValue()
		{
			return (int)this._hi;
		}

		public bool IsZero
		{
			get
			{
				return this._hi == 0.0 && this._lo == 0.0;
			}
		}

		public bool IsNegative
		{
			get
			{
				return this._hi < 0.0 || (this._hi == 0.0 && this._lo < 0.0);
			}
		}

		public bool IsPositive()
		{
			return this._hi > 0.0 || (this._hi == 0.0 && this._lo > 0.0);
		}

		public static bool IsNaN(DD value)
		{
			return double.IsNaN(value._hi);
		}

		public static bool IsInfinity(DD value)
		{
			return double.IsInfinity(value._hi);
		}

		public bool Equals(DD y)
		{
			return y._hi.Equals(this._hi) && y._lo.Equals(this._lo);
		}

		public static bool operator ==(DD lhs, DD rhs)
		{
			return lhs._hi == rhs._hi && lhs._lo == rhs._lo;
		}

		public static bool operator !=(DD rhs, DD lhs)
		{
			return !(rhs == lhs);
		}

		public bool GreaterThan(DD y)
		{
			return this._hi > y._hi || (this._hi == y._hi && this._lo > y._lo);
		}

		public bool GreaterOrEqualThan(DD y)
		{
			return this._hi > y._hi || (this._hi == y._hi && this._lo >= y._lo);
		}

		public bool LessThan(DD y)
		{
			return this._hi < y._hi || (this._hi == y._hi && this._lo < y._lo);
		}

		public bool LessOrEqualThan(DD y)
		{
			return this._hi < y._hi || (this._hi == y._hi && this._lo <= y._lo);
		}

		public int CompareTo(DD other)
		{
			if (this._hi < other._hi)
			{
				return -1;
			}
			if (this._hi > other._hi)
			{
				return 1;
			}
			if (this._lo < other._lo)
			{
				return -1;
			}
			if (this._lo > other._lo)
			{
				return 1;
			}
			return 0;
		}

		public int CompareTo(object o)
		{
			DD dd = (DD)o;
			if (this._hi < dd._hi)
			{
				return -1;
			}
			if (this._hi > dd._hi)
			{
				return 1;
			}
			if (this._lo < dd._lo)
			{
				return -1;
			}
			if (this._lo > dd._lo)
			{
				return 1;
			}
			return 0;
		}

		public string Dump()
		{
			return string.Format(NumberFormatInfo.InvariantInfo, "DD<{0}, {1}>", new object[]
			{
				this._hi,
				this._lo
			});
		}

		public override string ToString()
		{
			int num = DD.Magnitude(this._hi);
			if (num >= -3 && num <= 20)
			{
				return this.ToStandardNotation();
			}
			return this.ToSciNotation();
		}

		public string ToStandardNotation()
		{
			string specialNumberString = this.GetSpecialNumberString();
			if (specialNumberString != null)
			{
				return specialNumberString;
			}
			int[] array = new int[1];
			string text = this.ExtractSignificantDigits(true, array);
			int num = array[0] + 1;
			string text2 = text;
			if (text[0] == '.')
			{
				text2 = "0" + text;
			}
			else if (num < 0)
			{
				text2 = "0." + new string('0', -num) + text;
			}
			else if (text.IndexOf('.') == -1)
			{
				int count = num - text.Length;
				string str = new string('0', count);
				text2 = text + str + ".0";
			}
			if (this.IsNegative)
			{
				return "-" + text2;
			}
			return text2;
		}

		public string ToSciNotation()
		{
			if (this.IsZero)
			{
				return DD.SCI_NOT_ZERO;
			}
			string specialNumberString = this.GetSpecialNumberString();
			if (specialNumberString != null)
			{
				return specialNumberString;
			}
			int[] array = new int[1];
			string text = this.ExtractSignificantDigits(false, array);
			string text2 = DD.SCI_NOT_EXPONENT_CHAR + array[0];
			if (text[0] == '0')
			{
				throw new InvalidOperationException("Found leading zero: " + text);
			}
			string str = "";
			if (text.Length > 1)
			{
				str = text.Substring(1);
			}
			string text3 = text[0].ToString() + "." + str;
			if (this.IsNegative)
			{
				return "-" + text3 + text2;
			}
			return text3 + text2;
		}

		private string ExtractSignificantDigits(bool insertDecimalPoint, int[] magnitudes)
		{
			DD dd = this.Abs();
			int num = DD.Magnitude(dd._hi);
			DD rhs = DD.Ten.Pow(num);
			dd /= rhs;
			if (dd.GreaterThan(DD.Ten))
			{
				dd /= DD.Ten;
				num++;
			}
			else if (dd.LessThan(DD.One))
			{
				dd *= DD.Ten;
				num--;
			}
			int num2 = num + 1;
			StringBuilder stringBuilder = new StringBuilder();
			int num3 = 31;
			for (int i = 0; i <= num3; i++)
			{
				if (insertDecimalPoint && i == num2)
				{
					stringBuilder.Append('.');
				}
				int num4 = (int)dd._hi;
				if (num4 >= 0)
				{
				}
				if (num4 < 0)
				{
					break;
				}
				bool flag = false;
				char value;
				if (num4 > 9)
				{
					flag = true;
					value = '9';
				}
				else
				{
					value = (char)(48 + num4);
				}
				stringBuilder.Append(value);
				dd = (dd - DD.ValueOf((double)num4)) * DD.Ten;
				if (flag)
				{
					dd += DD.Ten;
				}
				bool flag2 = true;
				int num5 = DD.Magnitude(dd._hi);
				if (num5 < 0 && System.Math.Abs(num5) >= num3 - i)
				{
					flag2 = false;
				}
				if (!flag2)
				{
					break;
				}
			}
			magnitudes[0] = num;
			return stringBuilder.ToString();
		}

		private string GetSpecialNumberString()
		{
			if (this.IsZero)
			{
				return "0.0";
			}
			if (DD.IsNaN(this))
			{
				return "NaN ";
			}
			return null;
		}

		private static int Magnitude(double x)
		{
			double num = System.Math.Abs(x);
			int num2 = (int)Math.Floor(Math.Log(num) / Math.Log(10.0));
			if (System.Math.Pow(10.0, (double)num2) * 10.0 <= num)
			{
				num2++;
			}
			return num2;
		}

		public static DD Parse(string str)
		{
			int i = 0;
			int length = str.Length;
			while (char.IsWhiteSpace(str[i]))
			{
				i++;
			}
			bool flag = false;
			if (i < length)
			{
				char c = str[i];
				if (c == '-' || c == '+')
				{
					i++;
					if (c == '-')
					{
						flag = true;
					}
				}
			}
			DD dd = default(DD);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			while (i < length)
			{
				char c2 = str[i];
				i++;
				if (char.IsDigit(c2))
				{
					double rhs = (double)(c2 - '0');
					dd *= DD.Ten;
					dd += rhs;
					num++;
				}
				else
				{
					if (c2 != '.')
					{
						if (c2 == 'e' || c2 == 'E')
						{
							string text = str.Substring(i);
							try
							{
								num3 = int.Parse(text);
								break;
							}
							catch (FormatException innerException)
							{
								throw new FormatException("Invalid exponent " + text + " in string " + str, innerException);
							}
						}
						throw new FormatException(string.Concat(new object[]
						{
							"Unexpected character '",
							c2.ToString(),
							"' at position ",
							i,
							" in string ",
							str
						}));
					}
					num2 = num;
				}
			}
			DD result = dd;
			int num4 = num - num2 - num3;
			if (num4 == 0)
			{
				result = dd;
			}
			else if (num4 > 0)
			{
				DD y = DD.Ten.Pow(num4);
				result = dd.Divide(y);
			}
			else if (num4 < 0)
			{
				DD y2 = DD.Ten.Pow(-num4);
				result = dd.Multiply(y2);
			}
			if (flag)
			{
				return result.Negate();
			}
			return result;
		}

		public override bool Equals(object obj)
		{
			return obj != null && !(obj.GetType() != typeof(DD)) && this.Equals((DD)obj);
		}

		public override int GetHashCode()
		{
			return this._hi.GetHashCode() * 397 ^ this._lo.GetHashCode();
		}

		public static readonly DD PI = new DD(System.Math.PI, 1.2246467991473532E-16);

		public static readonly DD TwoPi = new DD(System.Math.PI*2, 2.4492935982947064E-16);

		public static readonly DD PiHalf = new DD(System.Math.PI*.5, 6.123233995736766E-17);

		public static readonly DD E = new DD(2.7182818284590451, 1.4456468917292502E-16);

		public static readonly DD NaN = new DD(double.NaN, double.NaN);

		public static readonly double Epsilon = 1.23259516440783E-32;

		private const double Split = 134217729.0;

		private readonly double _hi;

		private readonly double _lo;

		private const int MaxPrintDigits = 32;

		private static readonly DD Ten = DD.ValueOf(10.0);

		private static readonly DD One = DD.ValueOf(1.0);

		private static readonly string SCI_NOT_EXPONENT_CHAR = "E";

		private static readonly string SCI_NOT_ZERO = "0.0E0";
	}
}
